package com.yxw.bamboo.core.send.event.mssql;

import com.yxw.bamboo.core.BytesHelper;
import com.yxw.bamboo.core.NetPortForward;
import com.yxw.bamboo.core.SocketChannel;
import com.yxw.bamboo.core.database.mssql.MsBufferWrite;
import com.yxw.bamboo.core.database.mssql.TDSType;
import com.yxw.bamboo.core.database.mysql.MySqlConfig;
import com.yxw.bamboo.core.database.sql.DbLog;
import com.yxw.bamboo.core.database.sql.Mock;
import com.yxw.bamboo.core.database.sql.MockData;
import com.yxw.bamboo.core.send.event.EventArgs;
import com.yxw.bamboo.core.send.event.SendEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class MsSqlNetDefaultBeforeSendEvent implements SendEvent {

    private final static Logger logger = LoggerFactory.getLogger(MsSqlNetDefaultBeforeSendEvent.class);
    @Autowired
    MsBufferWrite msBufferWrite;
    @Autowired
    DbLog dbLog;

    @Override
    public void process(Object eventSource, EventArgs eventArgs) throws Exception {

        NetPortForward netPortForward=(NetPortForward)eventSource;
        SocketChannel channel=netPortForward.getChannel();
        byte[] des=(byte[])eventArgs.getArg();
        String[] sqlPWDPluginNames= MySqlConfig.getMySqlPwdPlugin();
        byte cryptoMeta=0;
        byte[] sqlCollationBytes=new byte[5];
        ByteBuffer byteBuffer= ByteBuffer.allocate(des.length).order(ByteOrder.LITTLE_ENDIAN);
        byteBuffer.put(des);
        if(channel.getChannelName().equals(SocketChannel.LOCAL_TO_REMOTE))
        {
            if(channel.getSocketStep()>=1)
            {
               if(channel.getSocketStep()>4)
                {
                    Integer offset=0;
                    if(des.length<=45)
                    {
                        return;
                    }

                    //sql语句长度小于8000是69位 如果大于8000是71位 且没有参数
                    //des 0号位置标示的是客户端请求类型 1标示的是jdbcTemplate 请求的 已经解析好的sql 语句
                    //3 标示的是 带参数的sql 语句
                    boolean bOut=false;
                    int count=69;
                    String sql="";
                    byte[] newBytes=null;
                    //sql语句长度
                    int sqlLength=-1;

                    byteBuffer.position(4);
                    short totalCount=byteBuffer.getShort();
                    int tdsMessageType=(int)des[0];
                    byteBuffer.position(byteBuffer.position()+15);

                    tdsMessageType=(int)des[16];


                    int sqlStartIndex=-1;
                    int sqlEndIndex=-1;
                    //无参数情况出现
                    if (tdsMessageType == 1) {
                        count = 30 + 16;
                    } else if (tdsMessageType == 3) {
                        count = 64;
                        byteBuffer.position(46);
                        short sqlTempLength=byteBuffer.getShort();
                        if(sqlTempLength!=-1)
                        {
                            count=48;
                            sqlLength = sqlTempLength*2;
                        }else
                        {
                            byteBuffer.position(62);
                            sqlLength = byteBuffer.getShort();
                        }


                        byteBuffer.position(count);
                    }

                    if(sqlLength>-1)
                    {
                        newBytes=new byte[sqlLength];
                    }else
                    {
                        newBytes=new byte[des.length-count];
                    }

                    System.arraycopy(des, count, newBytes, 0, newBytes.length);
                    byte[] covertByts=BytesHelper.bigLittleCovert(newBytes);
                    sql=new String(covertByts,"UTF-16");
                    ;
                    offset++;
                    dbLog.addLog(channel.getHostId(),channel.getSocketHashCode(),channel.getSocketStep(),offset,"SQL",sql);
                    MockData mockData= Mock.hitMsSql(sql,channel.getDbINfo().getUserName(),channel.getDbINfo().getDbName());


                    if(mockData!=null)
                    {
                        if(tdsMessageType==1)
                        {
                            byte[] expByte=BytesHelper.toUCS16(mockData.getReplaceSql());
                            byte[] newSendByte=new byte[expByte.length+30+16];
                            System.arraycopy(des, 0, newSendByte, 0, 30+16);
                            System.arraycopy(expByte, 0, newSendByte, 30+16, expByte.length);
                            newSendByte[3]=(byte) (newSendByte.length>>8&255);
                            newSendByte[4]=(byte) (newSendByte.length>>0&255);
                            newSendByte[18]=(byte) ((newSendByte.length-16)>>8&255);
                            newSendByte[19]=(byte) ((newSendByte.length-16)>>0&255);
                            String sendData=new String(newSendByte);
                            logger.info(channel.getSocketHashCode()+"命中---新发送的sql："+sendData);
                            logger.info(Arrays.toString(newSendByte));
                            eventArgs.setResult(newSendByte);
                            offset++;
                            dbLog.addLog(channel.getHostId(),channel.getSocketHashCode(),channel.getSocketStep(),offset,"SQL",mockData.getReplaceSql());
                        }else if (tdsMessageType==3)
                        {
                            //方案一可以将dst改成1
                            byte[] expByte=BytesHelper.toUCS16(mockData.getReplaceSql().trim());
                            byte[] newSendByte=new byte[expByte.length+30+16];
                            System.arraycopy(des, 0, newSendByte, 0, 30+16);
                            System.arraycopy(expByte, 0, newSendByte, 46, expByte.length);
                            newSendByte[5]=(byte) (newSendByte.length>>8&255);
                            newSendByte[4]=(byte) (newSendByte.length>>0&255);
                            newSendByte[18]=(byte) ((newSendByte.length-16)>>8&255);
                            newSendByte[19]=(byte) ((newSendByte.length-16)>>0&255);
                            newSendByte[16]=1;
                            String sendData=new String(newSendByte);
                            System.out.println(channel.getSocketHashCode()+"命中---新发送的sql："+sendData);
                            logger.info(Arrays.toString(newSendByte));
                            eventArgs.setResult(newSendByte);
                            offset++;
                            dbLog.addLog(channel.getHostId(),channel.getSocketHashCode(),channel.getSocketStep(),offset,"SQL",mockData.getReplaceSql());
                        }


                    }

                }

            }
        }else //
        {
            if(channel.getSocketStep()==4) {

                String regex = "\\'.*\\'";
                Pattern pattern = Pattern.compile(regex);
                String data = new String(des);
                Matcher matcher = pattern.matcher(data);
                if (matcher.find()) {
                    channel.getDbINfo().setDbName(matcher.toMatchResult().group(0));
                }
            }
        }
    }
}
